package oop.core.ai;

import oop.core.area.DamageAreaEffect;
import oop.core.entity.Avatar;
import oop.core.entity.Entity;
import oop.core.entity.NPC;
import oop.core.map.GameMap;
import oop.core.map.Location;
import oop.core.med.NPCMovementMediator;

/**
 * AI behavior: if within range of avatar, move to avatar, else just randomly move
 *
 */
public class AggressiveAI extends AI {
        private Avatar avatar;
        private Location lastKnownLocation;
        private Location lastNPCLocation;
        
        /**
         * AgressiveAI constructor.
         * @param avatar
         * @param movementMediator
         * @param gameMap
         * @param npc
         */
        public AggressiveAI(Avatar avatar, NPCMovementMediator movementMediator, GameMap gameMap, NPC npc){
                super(movementMediator, gameMap, npc);
                this.avatar = avatar;
                this.lastKnownLocation = null;
                this.lastNPCLocation = null;
        }
        
        /**
         * Overrides move to implement the AI behavior.
         */
        public void move() {
        		boolean visible = avatar.isVisible();
                NPCMovementMediator movementMediator = getMovementMediator();
                if(withinRange(avatar) && visible){
                		int direction = faceEntity(avatar.getLoc());
                		if(!checkFuturePosition(direction)){
                			movementMediator.moveEntity(direction);
							lastKnownLocation = avatar.getLoc();
							if(getNpc().getLoc() != lastNPCLocation)
									lastNPCLocation = getNpc().getLoc();
							}
								
                		else if(movementMediator.getCanMove()){
                			randomMove();
                			if(getNpc().getLoc() != lastNPCLocation)
                            	lastNPCLocation = getNpc().getLoc();
                		}
                }
                else if(withinRange(lastKnownLocation) && !visible){
                		int direction = faceEntity(lastKnownLocation);
                		if(!checkFuturePosition(direction))
                			movementMediator.moveEntity(direction);
                		if(getNpc().getLoc() != lastNPCLocation)
                        	lastNPCLocation = getNpc().getLoc();
                		else if(movementMediator.getCanMove()){
                			randomMove();
                			if(getNpc().getLoc() != lastNPCLocation)
                            	lastNPCLocation = getNpc().getLoc();
                		}	
                }
                else{
                        randomMove();
                        if(getNpc().getLoc() != lastNPCLocation)
                        	lastNPCLocation = getNpc().getLoc();
                }
        }
    	
        /**
         * Return a direction (int) that faces the NPC towards the Avatar.
         * @param l
         * @return
         */
    	public int faceEntity(Location l){
    		int direction = 0;
    		int xDist = getNpc().getXLoc()- l.getXPos();
    		int yDist = getNpc().getYLoc() - l.getYPos();
    		
    		if(xDist == 0){
    			if(yDist>0){
    				direction = 2;
    			}
    			else if(yDist<0){
    				direction = 8;
    			}
    		}
    		else if(yDist == 0){
    			if(xDist>0){
    				direction = 6;
    			}
    			else if(xDist<0){
    				direction = 4;
    			}
    		}
    		else if(xDist>0 && yDist>0){
    			direction = 3;
    		}
    		else if(xDist<0 && yDist>0){
    			direction = 1;
    		}
    		else if(xDist>0 && yDist<0){
    			direction = 9;
    		}
    		else if(xDist<0 && yDist<0){
    			direction = 3;
    		}
    		return direction;
    	}
    	
    	/**
    	 * Checks if the NPC is within range of the Avatar.
    	 * @param e
    	 * @return
    	 */
    	public boolean withinRange(Entity e){
    		Location eLoc = e.getLoc();
    		Location entityLoc = getNpc().getLoc();
    		return getNpc().getViewRange() >= Location.distance(eLoc, entityLoc);
    	}
    	
    	/**
    	 * Checks if the NPC is within range of a location.
    	 * @param l
    	 * @return
    	 */
    	public boolean withinRange(Location l){
    		Location entityLoc = getNpc().getLoc();
    		return getNpc().getViewRange() >= Location.distance(l,entityLoc);
    	}

    	/**
    	 * get/set methods
    	 */
		public Avatar getAvatar() {
			return avatar;
		}

		public void setAvatar(Avatar avatar) {
			this.avatar = avatar;
		}

		public Location getLastKnownLocation() {
			return lastKnownLocation;
		}

		public void setLastKnownLocation(Location lastKnownLocation) {
			this.lastKnownLocation = lastKnownLocation;
		}
}
